package cn.test.service.impl;

import cn.test.mapper.StockBlockRtInfoMapper;
import cn.test.mapper.StockBusinessMapper;
import cn.test.mapper.StockMarketIndexInfoMapper;
import cn.test.mapper.StockRtInfoMapper;
import cn.test.pojo.domain.*;
import cn.test.pojo.entity.StockBusiness;
import cn.test.pojo.entity.StockMarketIndexInfo;
import cn.test.pojo.vo.StockInfoConfig;
import cn.test.service.StockService;
import cn.test.utils.DateTimeUtil;
import cn.test.vo.resp.PageResult;
import cn.test.vo.resp.R;
import cn.test.vo.resp.ResponseCode;
import com.alibaba.excel.EasyExcel;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author bigBear
 * @version 1.0
 * @date 2024-10-21 13:03
 */
@Service("stockService")
@Slf4j
public class StockServiceImpl implements StockService {

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private StockInfoConfig stockInfoConfig;

    @Autowired
    private StockBusinessMapper stockBusinessMapper;

    @Autowired
    private StockBlockRtInfoMapper stockBlockRtInfoMapper;

    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;

    /**
     * 获取所有指数
     *
     * @return
     */
    @Override
    public R<List<InnerMarketDomain>> innerIndexAll() {
        //1.获取国内A股大盘的id集合
        List<String> inners = stockInfoConfig.getInner();
        //2.获取最近股票交易日期
        Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO mock测试数据
        lastDate = DateTime.parse("2022-01-02 09:32:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //3.将获取的java  Date传入接口
        List<InnerMarketDomain> list = stockMarketIndexInfoMapper.getMarketInfo(inners, lastDate);
        //4.返回查询结果
        return R.ok(list);
    }

    /**
     * 获取板块信息
     *
     * @return
     */
    @Override
    public R<List<StockBlockDomain>> sectorAllLimit10() {
        //1.获取最新交易时间点
        Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO mock测试数据
        lastDate = DateTime.parse("2021-12-21 14:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        List<StockBlockDomain> list = stockBlockRtInfoMapper.sectorAllLimit10(lastDate);
        if (CollectionUtils.isEmpty(list)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA.getMessage());
        }
        return R.ok(list);
    }

    /**
     * 分页查询股票最新数据，并按照涨幅倒序排序
     *
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public R<PageResult> getStockPageInfo(Integer page, Integer pageSize) {
        //1.设置PageHelper分页参数
        PageHelper.startPage(page, pageSize);
        //2.获取最近股票交易时间点
        Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO mock测试数据
        curDate = DateTime.parse("2022-06-07 15:00:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //3.调用mapper层查询数据
        List<StockUpdownDomain> infos = stockRtInfoMapper.getNewestStockInfo(curDate);
        if (CollectionUtils.isEmpty(infos)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA);
        }
        //4.组装PageInfo对象，获取分页的具体信息
        PageResult<StockUpdownDomain> pageResult = new PageResult<>(new PageInfo<>(infos));
        //5.响应数据
        return R.ok(pageResult);
    }

    /**
     * 获取涨幅前4的股票信息
     *
     * @return
     */
    @Override
    public R<List<StockRtDomain>> getStockIncreaseBy4() {
        //获取最近股票交易时间点
        Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO mock测试数据
        curDate = DateTime.parse("2021-12-30 10:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        List<StockRtDomain> list = stockRtInfoMapper.getStockIncreaseBy4(curDate);
        return R.ok(list);
    }

    /**
     * 获取涨跌统计信息
     *
     * @return
     */
    @Override
    public R<Map<String, List>> getStockUpDownCount() {
        //1.获取最新股票交易时间点
        Date endTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO mock测试数据
        endTime = DateTime.parse("2022-01-06 14:25:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.获取最新交易时间对应的开盘时间
        Date openTime = DateTimeUtil.getOpenDate(DateTimeUtil.getLastDate4Stock(DateTime.now())).toDate();
        openTime = DateTime.parse("2022-01-06 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //3.查询涨停数据，1-涨停 0-跌停
        List<Map> upList = stockRtInfoMapper.getStockUpDownCount(openTime, endTime, 1);
        List<Map> downList = stockRtInfoMapper.getStockUpDownCount(openTime, endTime, 0);
        //4.组装数据
        HashMap<String, List> data = new HashMap<>();
        data.put("upList", upList);
        data.put("downList", downList);
        //5.响应数据
        return R.ok(data);
    }

    @Override
    public void exportStockUndownInfo(HttpServletResponse response, Integer page, Integer pageSize) {
        R<PageResult> stockPageInfo = this.getStockPageInfo(page, pageSize);
        PageResult data = stockPageInfo.getData();
        List<StockUpdownDomain> rows = data.getRows();
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        try {
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("股票信息", "UTF-8").replaceAll("\\+", "%20");
            //设置默认文件名称，兼容一些特殊浏览器
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), StockUpdownDomain.class).sheet("股票信息").doWrite(rows);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("当前导出数据异常，当前页：{},每页大小：{}，异常信息：{}", page, pageSize, e.getMessage());
        }
    }

    /**
     * 统计国内A股大盘T日和T-1日成交量对比功能（成交量为沪市和深市成交量之和）
     *
     * @return
     */
    @Override
    public R<Map<String, List>> stockTradeVol4InnerMarket() {
        //1.获取T日日期范围
        DateTime tDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date tEndDate = tDateTime.toDate(); //T日当前时间
        //1.1 TODO mock测试数据
        tEndDate = DateTime.parse("2022-01-03 14:40:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        DateTime openDateTime = DateTimeUtil.getOpenDate(tDateTime);
        Date tOpenDate = openDateTime.toDate(); //T日开盘时间
        tOpenDate = DateTime.parse("2022-01-03 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.获取T-1日日期范围
        DateTime t1DateTime = DateTimeUtil.getPreviousTradingDay(tDateTime);
        Date t1EndDate = t1DateTime.toDate(); //T-1日当前时间
        t1EndDate = DateTime.parse("2022-01-02 14:40:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        DateTime t1OpenDateTime = DateTimeUtil.getOpenDate(t1DateTime);
        Date t1OpenDate = t1OpenDateTime.toDate();
        t1OpenDate = DateTime.parse("2022-01-02 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //3.获取股票编码，调用mapper
        List<String> inner = stockInfoConfig.getInner();
        //T日
        List<Map> amtList = stockMarketIndexInfoMapper.stockTradeVol4InnerMarket(tOpenDate, tEndDate, inner);
        //T-1日
        List<Map> yesAmtList = stockMarketIndexInfoMapper.stockTradeVol4InnerMarket(t1OpenDate, t1EndDate, inner);
        //4.组装数据
        HashMap<String, List> data = new HashMap<>();
        data.put("amtList", amtList);
        data.put("yesAmtList", yesAmtList);
        //5.响应
        return R.ok(data);
    }

    /**
     * 查询当前时间下股票的涨跌幅度区间统计功能
     * 如果当前日期不在有效时间内，则以最近的一个股票交易时间作为查询点
     *
     * @return
     */
    @Override
    public R<Map<String, Object>> getStockUpDown() {
        //1.获取T日日期范围
        DateTime curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date curDate = curDateTime.toDate(); //T日当前时间
        //1.1 TODO mock测试数据
        curDate = DateTime.parse("2022-01-06 09:55:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.调用mapper
        List<Map> list = stockRtInfoMapper.getStockUpDown(curDate);
        List<String> orderSections = stockInfoConfig.getUpDownRange();
        //思路：利用List集合的属性，然后顺序编译，找出每个标题对应的map，然后维护到一个新的List集合下即可
//        List<Map> orderMaps =new ArrayList<>();
//        for (String title : orderSections) {
//            Map map=null;
//            for (Map m : maps) {
//                if (m.containsValue(title)) {
//                    map=m;
//                    break;
//                }
//            }
//            if (map==null) {
//                map=new HashMap();
//                map.put("count",0);
//                map.put("title",title);
//            }
//            orderMaps.add(map);
//        }
        //方式2：使用lambda表达式指定
        List<Map> orderMaps = orderSections.stream().map(title -> {
            Map mp = null;
            Optional<Map> op = list.stream().filter(m -> m.containsValue(title)).findFirst();
            //判断是否存在符合过滤条件的元素
            if (op.isPresent()) {
                mp = op.get();
            } else {
                mp = new HashMap();
                mp.put("count", 0);
                mp.put("title", title);
            }
            return mp;
        }).collect(Collectors.toList());
        //3.封装数据
        HashMap<String, Object> data = new HashMap<>();
        //获取指定日期格式的字符串
        String curDateStr = new DateTime(curDate).toString(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        data.put("time", curDateStr);
        data.put("infos", orderMaps);
        //4.响应数据
        return R.ok(data);
    }

    /**
     * 功能描述：查询单个个股的分时行情数据，也就是统计指定股票T日每分钟的交易数据；
     * 如果当前日期不在有效时间内，则以最近的一个股票交易时间作为查询时间点
     *
     * @param code 股票编码
     * @return
     */
    @Override
    public R<List<Stock4MinuteDomain>> stockScreenTimeSharing(String code) {
        //1.获取最近最新的交易时间点和对应的开盘日期
        //1.1 获取最近有效时间点
        DateTime lastDate4Stock = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date endTime = lastDate4Stock.toDate();
        //TODO mockdata
        endTime = DateTime.parse("2021-12-30 14:47:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //1.2 获取最近有效时间点对应的开盘日期
        DateTime openDateTime = DateTimeUtil.getOpenDate(lastDate4Stock);
        Date startTime = openDateTime.toDate();
        //TODO MOCK DATA
        startTime = DateTime.parse("2021-12-30 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.根据股票code和日期范围查询
        List<Stock4MinuteDomain> list = stockRtInfoMapper.getStockInfoByCodeAndDate(code, startTime, endTime);
        //判断非空处理
        if (CollectionUtils.isEmpty(list)) {
            list = new ArrayList<>();
        }
        //3.返回响应数据
        return R.ok(list);
    }

    /**
     * 单个个股日K 数据查询 ，可以根据时间区间查询数日的K线数据
     *
     * @param stockCode 股票编码
     */
    @Override
    public R<List<Stock4EvrDayDomain>> stockCreenDkLine(String stockCode) {
        //1.获取查询的日期范围
        //1.1 获取截止时间
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date endTime = endDateTime.toDate();
        //TODO MOCKDATA
        endTime = DateTime.parse("2022-01-07 15:00:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //1.2 获取开始时间
        DateTime startDateTime = endDateTime.minusDays(10);
        Date startTime = startDateTime.toDate();
        //TODO MOCKDATA
        startTime = DateTime.parse("2022-01-01 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.调用mapper接口获取查询的集合信息-方案1
        List<Stock4EvrDayDomain> data = stockRtInfoMapper.getStockInfo4EvrDay(stockCode, startTime, endTime);
        //3.组装数据，响应
        return R.ok(data);
    }


}
